package cn.kmsoft.stgeometry.util;

import cn.kmsoft.stgeometry.landm.*;
import cn.kmsoft.common.utils.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.geojson.feature.FeatureJSON;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;


public class Shp2Txt {
    private static final Logger logger = LoggerFactory.getLogger(Shp2Txt.class);

    public static void main(String[] args) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss-SSS");
        String beginTime = sdf.format(new Date());

        System.out.println();
        System.out.println(String.format("---开始处理---, %s ", beginTime));
        System.out.println();
        /**********************开始处理*************************/

        shp2txt_bat();

        /**********************结束处理*************************/
        String endTime = sdf.format(new Date());
        System.out.println();
        System.out.println(String.format("---结束处理---,  %s ", endTime));
        System.out.println();
    }

    public static void shp2txt_bat() {
        String encoding = "utf-8";
        encoding = "gbk";
        //******************1.第一个可能需要修改的地方******************
        String shpfile = "D:\\temp\\dhtool\\XXZX_TEST\\XXZX_YZFX_STHX3_prj.shp";
        String txtPath = "D:\\temp\\dhtool\\XXZX_TEST\\TXT";

        System.out.println("**************输入shp数据：" + shpfile);
        System.out.println("**************输入txt结果：" + txtPath);

        ShapefileDataStore shpDataStore = null;
        File file = new File(shpfile);

        try {
            URL url = file.toURI().toURL();
            shpDataStore = new ShapefileDataStore(url);
            shpDataStore.setCharset(Charset.forName(encoding));
            String typeName = shpDataStore.getTypeNames()[0];
            //******************2.第二个可能需要修改的地方******************
            //String dzjghFieldName = "电子监管号";
            //String dzjghFieldName = "DZJGH";
            //String dzjghFieldName = "Color";
            //String dzjghFieldName = "PFWH";
            String dzjghFieldName = "PZWH";
            //String dzjghFieldName = "CBPWH";
            //String dzjghFieldName = "JSSCBH";
            //String dzjghFieldName = "批复文号";
            //String dzjghFieldName = "序号2";

            //存储电子监管号，保证电子监管号不重复
            Set<String> dzjghSet = new HashSet<String>();

            SimpleFeatureSource featureSource = shpDataStore.getFeatureSource(typeName);
            SimpleFeatureCollection feaCollections = featureSource.getFeatures();
            SimpleFeatureIterator feaIter = feaCollections.features();
            int numOfFeature = 0;
            while (feaIter.hasNext()) {
                SimpleFeature feature = feaIter.next();
                numOfFeature++;

                String dzjgh = "";
                Property prop = feature.getProperty(dzjghFieldName);
                if (prop == null) {
                    dzjgh = "";
                } else {
                    dzjgh = prop.getValue().toString();
                }

                //关键字段dzjgh为空，则采用随机来命名
                if (StringUtil.isNullOrEmpty(dzjgh)) {
                    Random rand = new Random();
                    dzjgh = "random_" + String.valueOf(rand.nextInt(100));
                }
                System.out.println("第 " + numOfFeature + "个Feature记录,DZJGH---" + dzjgh);
                
                dzjghSet.add(dzjgh);
                feature = null;
            }
            feaIter.close();

            int dzjghCount = dzjghSet.size();
            System.out.println("电子监管号个数为： " + dzjghCount);

            int index = 0;
            Iterator<String> it = dzjghSet.iterator();
            while (it.hasNext()) {

                index++;

                String dzjgh = it.next();
                System.out.println(String.format("---正在处理第 %s 个电子监管号, %s ", index, dzjgh));
                //String dzjgh ="5001022017A00657";

                FilterFactory2 filterFactory = CommonFactoryFinder.getFilterFactory2();
                //查询筛选
                Filter filter = (Filter) filterFactory.equals(filterFactory.property(dzjghFieldName), filterFactory.literal(dzjgh));
                SimpleFeatureCollection subCollections = featureSource.getFeatures(filter);

                //输出txt路径
                String txtfile = txtPath + "\\" + dzjgh + ".txt";

                shp2txt(subCollections, txtfile); //数据处理

            }

            shpDataStore.dispose();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 将一个shp文件转换为txt坐标串，技术细节中间使用land对象
     * @param shppath
     * @param txtpath
     */
    public static boolean shp2txt(String shppath, String txtpath,String encoding) {
        boolean bSuccess=false;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dynProductDateStr = sdf.format(new Date());
        if (StringUtil.isNullOrEmpty(encoding)) {
            encoding = "uft-8";
        }

        System.out.println();
        System.out.println(String.format("--->shp2txt, input shppath: %s",shppath));
        File shpfile = new File(shppath);
        if( !shpfile.exists()){
            return bSuccess;
        }

        ShapefileDataStore shpDataStore = null;
        try {
            String crsName = JTSGeometryWKTUtil.getShpCrsName(shppath);
            String wkid = CrsUtil.getWkidByCrsName(crsName);

            LandHeader landHeader=new LandHeader();
            landHeader.setFormatVersion("1.0版本");
            landHeader.setDataProduceOrg("重庆市规划和自然资源调查监测院");
            landHeader.setProduceDate(dynProductDateStr);
            landHeader.setCoordinateSystem("2000国家大地坐标系");
            landHeader.setDegreeNo("3");//几度分带
            landHeader.setProjectionType("高斯克吕格");
            landHeader.setUnit("米");
            landHeader.setDegreeNum(wkid);
            landHeader.setPrecision("0.001");//精度
            landHeader.setConversionParameter("0,0,0,0,0,0,1");//精度

            URL url = shpfile.toURI().toURL();
            shpDataStore = new ShapefileDataStore(url);
            shpDataStore.setCharset(Charset.forName(encoding));
            String typeName = shpDataStore.getTypeNames()[0];
            SimpleFeatureSource featureSource = shpDataStore.getFeatureSource(typeName);
            SimpleFeatureCollection feaCollections = featureSource.getFeatures();

            //SHP转换为TXT
            shp2txt(feaCollections,txtpath, landHeader);

            shpDataStore.dispose();

            bSuccess=true;
        } catch (Exception ex) {
            bSuccess=false;
            ex.printStackTrace();
        }

        return bSuccess;
    }

    /**
     * shp2txt转换，主要用于根据pzwh字段开展txt批量文件转换
     *
     * @param feaCollections
     * @param txtfile
     */
    public static void shp2txt(SimpleFeatureCollection feaCollections, String txtfile) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dynProductDateStr = sdf.format(new Date());

        FeatureJSON fjson = new FeatureJSON();
        try {
            //land
            Land land = new Land();

            //******************3.第三个可能需要修改的地方******************
            land.setFormatVersion("1.0版本");
            //land.setDataProduceOrg("");
            land.setDataProduceOrg("重庆市规划和自然资源调查监测院");
            //land.setProduceDate("2019-06-18");
            land.setProduceDate(dynProductDateStr);
            //land.setCoordinateSystem("80国家大地坐标系");
            land.setCoordinateSystem("2000国家大地坐标系");
            //land.setCoordinateSystem("CQDL");
            land.setDegreeNo("3");//几度分带
            land.setProjectionType("高斯克吕格");
            land.setUnit("米");
            //land.setDegreeNum("35");//带号
            land.setDegreeNum("36");
            //land.setDegreeNum("37");
            land.setPrecision("0.001");//精度
            land.setConversionParameter("0,0,0,0,0,0,1");//精度

            //遍历要素
            int blockNum = 0;
            SimpleFeatureIterator feaIter = (SimpleFeatureIterator) feaCollections.features();
            while (feaIter.hasNext()) {
                SimpleFeature feature = feaIter.next();

                //block
                Block landBlock = new Block();
                blockNum++;

                //1-获取Feature基本信息
                int attrCount = feature.getAttributeCount();
                String the_geom = feature.getAttribute("the_geom").toString();

                //将shp的feature转换为geojson串
                StringWriter strWriter = new StringWriter();
                fjson.writeFeature(feature, strWriter);
                String feaJsonString = strWriter.toString();
                //System.out.println(feaJsonString);

                //转换json串的为json对象
                com.alibaba.fastjson.JSONObject feaObject = JSON.parseObject(feaJsonString);
                String feaId = feaObject.getString("id");
                String feaType = feaObject.getString("type");

                //2-获取Feature属性信息
                System.out.println();
                System.out.println("---属性字段：");
                com.alibaba.fastjson.JSONObject feaProperties = feaObject.getJSONObject("properties");
                for (Map.Entry<String, Object> entry : feaProperties.entrySet()) {
                    String fieldName = entry.getKey();
                    String fieldValue = entry.getValue().toString();
                    //shp的所有字段属性
                    landBlock.getbAttrs().put(fieldName, fieldValue);
                    System.out.println(fieldName + ":" + fieldValue);
                }

                //******************4.第四个可能需要修改的地方(不用改这里，规范输入的shp字段最好)******************
                //dkmj 地块面积单位：土地登记系统供地数据的单位通常为公顷
                Double dkmj = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("TXJSMJ")) ?
                        0.00 : Double.parseDouble(landBlock.getbAttrs().get("TXJSMJ").toString());//图形计算面积，单位公顷
                //String dkbh = String.format("地块%s", blockNum);
                String dkbh = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("DKBH")) ?
                        "" : landBlock.getbAttrs().get("DKBH").toString();
                String dkmc = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("XMMC")) ?
                        "" : landBlock.getbAttrs().get("XMMC").toString();
                String jltxsx = "面";
                String tfh = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("TFH")) ?
                        "" : landBlock.getbAttrs().get("TFH").toString();//图幅号
                String dkyt = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("TDYT")) ?
                        "" : landBlock.getbAttrs().get("TDYT").toString();
                //TXT标准坐标文件所需的关键属性
                landBlock.setDkmj(dkmj);
                landBlock.setDkbh(dkbh);
                landBlock.setDkmc(dkmc);
                landBlock.setJltxsx(jltxsx);
                landBlock.setTfh(tfh);
                landBlock.setDkyt(dkyt);

                //3.获取Geometry相关信息
                com.alibaba.fastjson.JSONObject geoObject = feaObject.getJSONObject("geometry");
                String feaGeoType = geoObject.getString("type");
                System.out.println();
                System.out.println("feaGeoType: " + feaGeoType);
                // geometry坐标串
                JSONArray feaGeoCoords = geoObject.getJSONArray("coordinates");
                for (int i = 0; i < feaGeoCoords.size(); i++) {
                    JSONArray jsonRings = feaGeoCoords.getJSONArray(i);
                    for (int j = 0; j < jsonRings.size(); j++) {
                        //ring
                        Ring blockRing = new Ring();
                        JSONArray jsonRing = jsonRings.getJSONArray(j);
                        for (int k = 0; k < jsonRing.size(); k++) {
                            JSONArray jsonCoords = jsonRing.getJSONArray(k);

                            // point
                            Point p = new Point();
                            Double x = Double.parseDouble(jsonCoords.get(0).toString());
                            Double y = Double.parseDouble(jsonCoords.get(1).toString());
                            //坐标点
                            p.setX(x);
                            p.setY(y);
                            System.out.println(String.format("%.3f, %.3f", x, y));

                            blockRing.getPoints().add(p);
                        }

                        landBlock.getRings().add(blockRing);
                    }
                }

                land.getBlocks().add(landBlock);
            }
            feaIter.close();

            //输出land中内容到txt文件中
            File outtxtfile = new File(txtfile);
            //PrintStream ps = new PrintStream(new FileOutputStream(outtxtfile));
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(txtfile), "GBK"), true);

            //基本信息
            pw.println("[属性描述]");
            pw.println("格式版本号=" + land.getFormatVersion());
            pw.println("数据产生单位=" + land.getDataProduceOrg());
            pw.println("数据产生日期=" + land.getProduceDate());
            pw.println("坐标系=" + land.getCoordinateSystem());
            pw.println("几度分带=" + land.getDegreeNo());
            pw.println("投影类型=" + land.getProjectionType());
            pw.println("计量单位=" + land.getUnit());
            pw.println("带号=" + land.getDegreeNum());
            pw.println("精度=" + land.getPrecision());
            pw.println("转换参数=" + land.getConversionParameter());

            //坐标序列
            pw.println("[地块坐标]");

            int blockCount = land.getBlocks().size();
            for (int i = 0; i < blockCount; i++) {
                Block block = land.getBlocks().get(i);
                int ringCount = block.getRings().size();

                //界址点数
                int jzdCount = 0;
                for (int j = 0; j < ringCount; j++) {
                    Ring ring = block.getRings().get(j);
                    int pointCount = ring.getPoints().size();

                    jzdCount += pointCount;
                }
                //加上最后的闭合点
                //jzdCount = jzdCount + 1;

                String dkmj = String.format("%.4f", block.getDkmj());
                String dkbh = block.getDkbh();
                int bhIndex = i + 1;
                //地块编号DKBH
                if (StringUtil.isNullOrEmpty(dkbh)) {
                    dkbh = "地块" + bhIndex;
                }
                String dkmc = block.getDkmc();
                String jltxsx = block.getJltxsx();
                String tfh = block.getTfh();
                String dkyt = block.getDkyt();

                //坐标序列台头
                //界址点数,地块面积,地块编号,地块名称,记录图形属性(点、线、面),图幅号,地块用途,地类编码,@
                String blockHeader = String.format("%s,%s,%s,%s,%s,%s,%s,%s,%s",
                        jzdCount, dkmj, dkbh, dkmc, jltxsx, tfh, dkyt, "地类编码", "@");
                //System.out.println(blockHeader);
                pw.println(blockHeader);

                for (int j = 0; j < ringCount; j++) {
                    Ring ring = block.getRings().get(j);
                    int pointCount = ring.getPoints().size();

                    int ringIndex = j + 1;
                    for (int k = 0; k < pointCount; k++) {
                        Point pt = ring.getPoints().get(k);
                        //String y = String.format("%.6f",pt.getY());
                        //String x = String.format("%.6f",pt.getX());
                        String y = String.format("%.3f", pt.getY());
                        String x = String.format("%.3f", pt.getX());

                        int jzdIndex = k + 1;
                        String jzdLabel = "J" + jzdIndex;
                        String line = String.format("%s,%s,%s,%s", jzdLabel, ringIndex, y, x);

                        pw.println(line);
                    }

                    //添加第一个界址点，形成闭合
	        		/*
	        		Point firstPt = ring.getPoints().get(0);	        			
        			String fy = String.format("%.3f",firstPt.getY());
        			String fx = String.format("%.3f",firstPt.getX());
        			String line = String.format("%s,%s,%s,%s", "J1", ringIndex, fy, fx);
        			*/
                    //pw.println(line);

                }
            }

            pw.flush();
            pw.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * shp2txt转换，主要用于征地审查中“用地红线范围”转换为txt
     *
     * @param feaCollections
     * @param txtfile
     * @param landHeader
     */
    public static void shp2txt(SimpleFeatureCollection feaCollections, String txtfile, LandHeader landHeader) {
        FeatureJSON fjson = new FeatureJSON();
        try {
            //land
            Land land = new Land(landHeader);

            //遍历要素
            int blockNum = 0;
            SimpleFeatureIterator feaIter = (SimpleFeatureIterator) feaCollections.features();
            while (feaIter.hasNext()) {
                SimpleFeature feature = feaIter.next();

                //block
                Block landBlock = new Block();
                blockNum++;

                //1-获取Feature基本信息
                int attrCount = feature.getAttributeCount();
                String the_geom = feature.getAttribute("the_geom").toString();

                //将shp的feature转换为geojson串
                StringWriter strWriter = new StringWriter();
                fjson.writeFeature(feature, strWriter);
                String feaJsonString = strWriter.toString();
                //System.out.println(feaJsonString);

                //转换json串的为json对象
                com.alibaba.fastjson.JSONObject feaObject = JSON.parseObject(feaJsonString);
                String feaId = feaObject.getString("id");
                String feaType = feaObject.getString("type");

                //2-获取Feature属性信息
                System.out.println();
                System.out.println("---属性字段：");
                com.alibaba.fastjson.JSONObject feaProperties = feaObject.getJSONObject("properties");
                for (Map.Entry<String, Object> entry : feaProperties.entrySet()) {
                    String fieldName = entry.getKey();
                    String fieldValue = entry.getValue().toString();
                    //shp的所有字段属性
                    landBlock.getbAttrs().put(fieldName, fieldValue);
                    System.out.println(fieldName + ":" + fieldValue);
                }

                //******************4.第四个可能需要修改的地方(不用改这里，规范输入的shp字段最好)******************
                //dkmj 地块面积单位：土地登记系统供地数据的单位通常为公顷
                Double dkmj = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("DKMJ")) ?
                        0.00 : Double.parseDouble(landBlock.getbAttrs().get("DKMJ").toString()) / 10000;//图形计算面积，单位公顷
                //String dkbh = String.format("地块%s", blockNum);
                String dkbh = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("DKBH")) ?
                        "" : landBlock.getbAttrs().get("DKBH").toString();
                String dkmc = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("DKMC")) ?
                        "" : landBlock.getbAttrs().get("DKMC").toString();
                String jltxsx = "面";
                String tfh = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("TFH")) ?
                        "" : landBlock.getbAttrs().get("TFH").toString();//图幅号
                String dkyt = StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("ZZLX")) ?
                        "" : landBlock.getbAttrs().get("ZZLX").toString();
                String kcdw =  StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("KCDW")) ?
                        "" : landBlock.getbAttrs().get("KCDW").toString();
                String kcdjrq =  StringUtil.isNullOrEmpty(landBlock.getbAttrs().get("KCDJRQ")) ?
                        "" : landBlock.getbAttrs().get("KCDJRQ").toString();
                //TXT标准坐标文件所需的关键属性
                landBlock.setDkmj(dkmj);
                landBlock.setDkbh(dkbh);
                landBlock.setDkmc(dkmc);
                landBlock.setJltxsx(jltxsx);
                landBlock.setTfh(tfh);
                landBlock.setDkyt(dkyt);

                land.setDataProduceOrg(kcdw);
                land.setProduceDate(kcdjrq);

                //3.获取Geometry相关信息
                com.alibaba.fastjson.JSONObject geoObject = feaObject.getJSONObject("geometry");
                String feaGeoType = geoObject.getString("type");
                System.out.println();
                System.out.println("feaGeoType: " + feaGeoType);
                // geometry坐标串
                JSONArray feaGeoCoords = geoObject.getJSONArray("coordinates");
                for (int i = 0; i < feaGeoCoords.size(); i++) {
                    JSONArray jsonRings = feaGeoCoords.getJSONArray(i);
                    for (int j = 0; j < jsonRings.size(); j++) {
                        //ring
                        Ring blockRing = new Ring();
                        JSONArray jsonRing = jsonRings.getJSONArray(j);
                        for (int k = 0; k < jsonRing.size(); k++) {
                            JSONArray jsonCoords = jsonRing.getJSONArray(k);

                            // point
                            Point p = new Point();
                            Double x = Double.parseDouble(jsonCoords.get(0).toString());
                            Double y = Double.parseDouble(jsonCoords.get(1).toString());
                            //坐标点
                            p.setX(x);
                            p.setY(y);
                            System.out.println(String.format("%.3f, %.3f", x, y));

                            blockRing.getPoints().add(p);
                        }

                        landBlock.getRings().add(blockRing);
                    }
                }

                land.getBlocks().add(landBlock);
            }
            feaIter.close();

            //输出land中内容到txt文件中
            File outtxtfile = new File(txtfile);
            //PrintStream ps = new PrintStream(new FileOutputStream(outtxtfile));
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(txtfile), "GBK"), true);

            //基本信息
            pw.println("[属性描述]");
            pw.println("格式版本号=" + land.getFormatVersion());
            pw.println("数据产生单位=" + land.getDataProduceOrg());
            pw.println("数据产生日期=" + land.getProduceDate());
            pw.println("坐标系=" + land.getCoordinateSystem());
            pw.println("几度分带=" + land.getDegreeNo());
            pw.println("投影类型=" + land.getProjectionType());
            pw.println("计量单位=" + land.getUnit());
            pw.println("带号=" + land.getDegreeNum());
            pw.println("精度=" + land.getPrecision());
            pw.println("转换参数=" + land.getConversionParameter());

            //坐标序列
            pw.println("[地块坐标]");

            int blockCount = land.getBlocks().size();
            for (int i = 0; i < blockCount; i++) {
                Block block = land.getBlocks().get(i);
                int ringCount = block.getRings().size();

                //界址点数
                int jzdCount = 0;
                for (int j = 0; j < ringCount; j++) {
                    Ring ring = block.getRings().get(j);
                    int pointCount = ring.getPoints().size();

                    jzdCount += pointCount;
                }
                //加上最后的闭合点
                //jzdCount = jzdCount + 1;

                String dkmj = String.format("%.4f", block.getDkmj());
                String dkbh = block.getDkbh();
                int bhIndex = i + 1;
                //地块编号DKBH
                if (StringUtil.isNullOrEmpty(dkbh)) {
                    dkbh = "地块" + bhIndex;
                }
                String dkmc = block.getDkmc();
                String jltxsx = block.getJltxsx();
                String tfh = block.getTfh();
                String dkyt = block.getDkyt();

                //坐标序列台头
                //界址点数,地块面积,地块编号,地块名称,记录图形属性(点、线、面),图幅号,地块用途,地类编码,@
                String blockHeader = String.format("%s,%s,%s,%s,%s,%s,%s,%s,%s",
                        jzdCount, dkmj, dkbh, dkmc, jltxsx, tfh, dkyt, "地类编码", "@");
                //System.out.println(blockHeader);
                pw.println(blockHeader);

                for (int j = 0; j < ringCount; j++) {
                    Ring ring = block.getRings().get(j);
                    int pointCount = ring.getPoints().size();

                    int ringIndex = j + 1;
                    for (int k = 0; k < pointCount; k++) {
                        Point pt = ring.getPoints().get(k);
                        //String y = String.format("%.6f",pt.getY());
                        //String x = String.format("%.6f",pt.getX());
                        String y = String.format("%.3f", pt.getY());
                        String x = String.format("%.3f", pt.getX());

                        int jzdIndex = k + 1;
                        String jzdLabel = "J" + jzdIndex;
                        String line = String.format("%s,%s,%s,%s", jzdLabel, ringIndex, y, x);

                        pw.println(line);
                    }

                    //添加第一个界址点，形成闭合
	        		/*
	        		Point firstPt = ring.getPoints().get(0);
        			String fy = String.format("%.3f",firstPt.getY());
        			String fx = String.format("%.3f",firstPt.getX());
        			String line = String.format("%s,%s,%s,%s", "J1", ringIndex, fy, fx);
        			*/
                    //pw.println(line);

                }
            }

            pw.flush();
            pw.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

}
